package net.lastcoder.ifserver;

import net.lastcoder.ifserver.auth.AuthManager;
import net.lastcoder.ifserver.command.CommandManager;
import net.lastcoder.ifserver.web.WebManager;
import net.lastcoder.ifserver.module.Module;
import net.lastcoder.ifserver.module.ModuleManager;
import net.lastcoder.ifserver.nio.ClientConnectionAcceptor;
import net.lastcoder.ifserver.nio.ConnectPrivacy;
import net.lastcoder.ifserver.packet.PacketParser;
import net.lastcoder.ifserver.node.NodeManager;
import net.lastcoder.ifserver.plugin.PluginManager;
import net.lastcoder.ifserver.route.EventHandlerManager;
import net.lastcoder.ifserver.route.PacketRouter;
import net.lastcoder.ifserver.session.SessionManager;
import net.lastcoder.ifserver.session.SessionHandler;
import net.lastcoder.ifserver.session.UlaID;
import net.lastcoder.ifserver.util.TaskEngine;
import net.lastcoder.ifserver.util.Version;

import org.apache.log4j.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Scanner;
import java.util.TimerTask;

/**ifserver，注意必须配置config路径
 * auth: WenYF
 * date: 2016/9/30
 */
public class Server {
    private static final Logger logger = LoggerFactory.getLogger(Server.class);
    
    private static Server instance;
    /**
     * 入口流量统计
     */
    public static volatile long inCount = 0;
    /**
     * 出口流量统计
     */
    public static volatile long outCount = 0;

    /**
     * 长连接入数据
     */
    public static volatile long inConnCount = 0;
    /**
     * 长连接出数据
     */
    public static volatile long outConnCount = 0;
    
    /**
     * http in
     */
    public static volatile long inHttpCount = 0;
    /**
     * http out
     */
    public static volatile long outHttpCount = 0;
    
    public long startTime = 0;
    
    public static Server getInstance() {
        return instance;
    }

    private ModuleManager moduleManager;
    private PluginManager pluginManager;
    private SessionManager sessionManager;
    private PacketRouter packetRouter;
    private EventHandlerManager eventHandlerManager;
    private SessionHandler sessionPacketHandler;
    private CommandManager commandManager;
    private AuthManager authManager;
    private NodeManager nodeManager;
    private WebManager webManager;
    private HashMap<String, Object> attributes;

    private ClientConnectionAcceptor clientAcceptor;
    private boolean isStopping;
    public Server() {
        instance = this;
        attributes = new HashMap<>();
        
        String runDir = System.getProperty("ifserverHome");
        File file = new File(runDir);
        System.out.println("home = " + file.getAbsolutePath());

        // 必须设置Home目录
        Globals.setHomeDirectory(file.getAbsolutePath());
        Globals.getHomeDirectory();

        Level level = Level.toLevel(Globals.getXMLProperty("log.all", "INFO"));
        org.apache.log4j.LogManager.getRootLogger().setLevel(level);

        version = new Version(1, 0, 1, Version.ReleaseStatus.Release, -1);
        logger.debug("developmentMode = " + Boolean.getBoolean("developmentMode"));

        PacketParser.ENABLE_PARSER_DEBUG = Globals.getXMLProperty("parser.log", false);

        domain = Globals.getXMLProperty("host.domain", "127.0.0.1");
        name = Globals.getXMLProperty("host.name", "ifserver");
        serverId = new UlaID(domain, UlaID.RESOURCE_SERVER);

        Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());

        if (Boolean.getBoolean("dos")) {
            //TaskEngine.getInstance().schedule(new Terminator(), 1000, 1000);
            new Thread(new Terminator(), "terminator").start();
        }

        moduleManager = ModuleManager.getInstance();
        pluginManager = new PluginManager(new File(file, "plugins"));

        loadModules();
        initModules();

        start();

        isStopping = false;
        startTime = System.currentTimeMillis();
    }

    public void start() {
        pluginManager.start();

        if (Globals.getXMLProperty("client.acceptor.enable", true)) {
            clientAcceptor = new ClientConnectionAcceptor();
            clientAcceptor.start();
        }
    }


    private UlaID serverId;
    private String domain;
    private String name;
    private Version version;

    private void loadModules() {
        // privacy
        ConnectPrivacy connectPrivacy = ConnectPrivacy.getInstance();

        sessionManager = SessionManager.getInstance();
        eventHandlerManager = EventHandlerManager.getInstance();
        sessionPacketHandler = new SessionHandler();
        commandManager = CommandManager.getInstance();
        packetRouter = new PacketRouter();
        authManager = AuthManager.getInstance();
        nodeManager = NodeManager.getInstance();
        webManager = WebManager.getInstance();

        moduleManager.addModule(connectPrivacy);
        moduleManager.addModule(sessionManager);
        moduleManager.addModule(packetRouter);
        moduleManager.addModule(eventHandlerManager);
        moduleManager.addModule(sessionPacketHandler);
        moduleManager.addModule(commandManager);
        moduleManager.addModule(authManager);
        moduleManager.addModule(nodeManager);
        moduleManager.addModule(webManager);
    }

    private void initModules() {
        for (Module module : moduleManager.getModules()) {
            module.init();
        }
    }

    private void destroyModules() {
        for (Module module : moduleManager.getModules()) {
            module.destroy();
        }
    }


    public Version getVersion() {
        return version;
    }

    public UlaID getServerId() {
        return serverId;
    }

    public void setServerId(UlaID serverId) {
        this.serverId = serverId;
    }

    public String getServerDomain() {
        return domain;
    }

    public String getServerName() {
        return name;
    }

    public boolean isSetupMode() {
        return true;
    }

    public void setAttribute(String key, Object obj) {
        attributes.put(key, obj);
    }
    
    public Object getAttribute(String key) {
        return attributes.get(key);
    }
    
    public Collection<Object> getAttributes() {
        return Collections.unmodifiableCollection(attributes.values());
    }
    
    private class ShutdownHookThread extends Thread {

        /**
         * <p>Logs the server shutdown.</p>
         */
        @Override
        public void run() {
            shutdownServer();
            logger.info("Server halted");
            System.err.println("Server halted");
        }
    }

    private void shutdownServer() {
        logger.info("ifserver stopping...");
        isStopping = true;
        
        // 先关闭定时任务
        TaskEngine.getInstance().shutdown();

        // 关闭插件，必须在module之前
        pluginManager.shutdown();
        
        // 关闭module
        destroyModules();

        if (clientAcceptor != null) {
            clientAcceptor.stop();
        }

        logger.info("ifserver stopped");
    }

    /**是否正在关闭，给关闭中的插件和模块可能需要用到
     * @return
     */
    public boolean isStopping() {
        return isStopping;
    }


    /**
     * 控制台输入
     */
    private class Terminator extends TimerTask {
        //private BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
        private Scanner scanner = new Scanner(System.in);
        @Override
        public void run() {
            while (true) {
                try {
                    if (scanner.hasNextLine()) {
                        String line = scanner.nextLine();
                        System.out.println(commandManager.processCommand(line));
                    }
                } catch (IllegalStateException ioe) {
                    System.err.println("error input, " + ioe.getMessage());
                } catch (Exception e) {
                    System.err.println("process error : " + e.getMessage());
                }
            }
        }
    }

    public PacketRouter getPacketRouter() {
        return packetRouter;
    }

    public SessionManager getSessionManager() {
        return sessionManager;
    }

    public EventHandlerManager getEventHandlerManager() {
        return eventHandlerManager;
    }

    public PluginManager getPluginManager() {
        return pluginManager;
    }

    public NodeManager getNodeManager(){
        return nodeManager;
    }


    public Module getModule(String name) {
        return moduleManager.getModule(name);
    }

    public WebManager getWebManager() {
        return webManager;
    }

    /**
     * @return 得到服务器启动时间
     */
    public long getStartTime() {
        return startTime;
    }
}
